﻿#region Header

// Written by Tobias Lekman, 2008. For more information and contact details, see http://www.lekman.com.
// 
// File released under Microsoft Public License (Ms-PL). For full details see http://www.microsoft.com/opensource/licenses.mspx
// 
// Conditions and Limitations
// 
// (A) No Trademark License- This license does not grant you rights to use any contributors' name, logo, or trademarks.
// 
// (B) If you bring a patent claim against any contributor over patents that you claim are infringed by the software, your patent license from such contributor to the software ends automatically.
// 
// (C) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and attribution notices that are present in the software.
// 
// (D) If you distribute any portion of the software in source code form, you may do so only under this license by including a complete copy of this license with your distribution. If you distribute any portion of the software in compiled or object code form, you may only do so under a license that complies with this license.
// 
// (E) The software is licensed "as-is." You bear the risk of using it. The contributors give no express warranties, guarantees or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular purpose and non-infringement. 

#endregion

#region Using Statements

using System;
using Microsoft.SharePoint;

#endregion

namespace CodePlex.Lekman.SharePoint.CacheDependencies
{
    /// <summary>
    /// Cache dependency objects for SharePoint lists.
    /// </summary>
    /// <example>
    /// To cache data using an <see cref="SPList"/> as dependency object:
    /// <code>
    /// HttpContext.Current.Cache.Add("YourKey",
    ///     dataToCache,
    ///     new SPListCacheDependency(sourceList),
    ///     Cache.NoAbsoluteExpiration,
    ///     Cache.NoSlidingExpiration,
    ///     CacheItemPriority.Normal,
    ///     null);
    /// </code>
    /// Optionally, you can monitor any property or schema change as well:
    /// <code>
    /// HttpContext.Current.Cache.Add("YourKey",
    ///     dataToCache,
    ///     new SPListCacheDependency(sourceList, true, true),
    ///     Cache.NoAbsoluteExpiration,
    ///     Cache.NoSlidingExpiration,
    ///     CacheItemPriority.Normal,
    ///     null);
    /// </code>
    /// Changes are checked for every ten seconds. To increase to, for example, 60 seconds:
    /// <code>
    /// HttpContext.Current.Cache.Add("YourKey",
    ///     dataToCache,
    ///     new SPListCacheDependency(sourceList, false, false, 60000),
    ///     Cache.NoAbsoluteExpiration,
    ///     Cache.NoSlidingExpiration,
    ///     CacheItemPriority.Normal,
    ///     null);
    /// </code>
    /// </example>
    public class SPListCacheDependency : SPObjectCacheDependency
    {
        #region Fields

        private readonly SPObjectCacheDependencyEventArgs eventArgs;
        private readonly int itemCount;
        private readonly DateTime lastModified;
        private readonly string properties;
        private readonly string schema;
        private readonly string uniqueId;

        #endregion

        #region Contructors

        /// <summary>
        /// Initializes a new instance of the SPListCacheDependency class.
        /// </summary>
        /// <param name="list">The list to base the dependency on.</param>
        public SPListCacheDependency(SPList list)
            : this(list,
                   false,
                   false) {}

        /// <summary>
        /// Initializes a new instance of the SPListCacheDependency class.
        /// </summary>
        /// <param name="list">The list to base the dependency on.</param>
        /// <param name="includePropertyChanges">true to watch any change to any property of the list.</param>
        /// <param name="includeSchemaChanges">true to watch any change to the schema definition of the list.</param>
        public SPListCacheDependency(SPList list,
                                     bool includePropertyChanges,
                                     bool includeSchemaChanges)
            : this(list,
                   includePropertyChanges,
                   includeSchemaChanges,
                   10000) {}

        /// <summary>
        /// Initializes a new instance of the SPListCacheDependency class.
        /// </summary>
        /// <param name="list">The list to base the dependency on.</param>
        /// <param name="includePropertyChanges">true to watch any change to any property of the list.</param>
        /// <param name="includeSchemaChanges">true to watch any change to the schema definition of the list.</param>
        /// <param name="interval">The interval in milliseconds to check the underlying object for changes.</param>
        public SPListCacheDependency(SPList list,
                                     bool includePropertyChanges,
                                     bool includeSchemaChanges,
                                     double interval)
            : base(interval)
        {
            lastModified = list.LastItemModifiedDate;
            if (list.LastItemDeletedDate > lastModified)
            {
                lastModified = list.LastItemDeletedDate;
            }
            itemCount = list.ItemCount;
            properties = includePropertyChanges
                             ? list.PropertiesXml
                             : string.Empty;
            schema = includeSchemaChanges
                         ? list.SchemaXml
                         : string.Empty;
            eventArgs = new SPObjectCacheDependencyEventArgs(
                list.ParentWeb.Site.ID,
                list.ParentWeb.ID,
                list.ID,
                0);
            uniqueId = list.ID.ToString() + list.ParentWeb.ID + list.ParentWeb.Site.ID;
        }

        #endregion

        #region Overrides of SPObjectCacheDependency

        /// <summary>
        /// Gets the <see cref="SPObjectCacheDependencyEventArgs"/> containing the information about the current SharePoint object.
        /// </summary>
        protected override SPObjectCacheDependencyEventArgs EventArgs
        {
            get
            {
                return eventArgs;
            }
        }

        /// <summary>
        /// Determines if a specific list is different in version than the contained object.
        /// </summary>
        /// <param name="source">The object instance to check for changes.</param>
        /// <returns>true if the object has changed.</returns>
        protected override bool HasObjectChanged(object source)
        {
            SPList list = (SPList) source;
            DateTime modified = list.LastItemModifiedDate;
            if (list.LastItemDeletedDate > modified)
            {
                modified = list.LastItemDeletedDate;
            }
            if (!string.IsNullOrEmpty(properties) &&
                properties != list.PropertiesXml)
            {
                return true;
            }
            if (!string.IsNullOrEmpty(schema) &&
                schema != list.SchemaXml)
            {
                return true;
            }
            return lastModified != modified || itemCount != list.ItemCount;
        }

        /// <summary>
        /// Retrieves a unique identifier for a <see cref="System.Web.Caching.CacheDependency" /> object formed of the ID of the list, its parent <see cref="SPWeb"/> and <see cref="SPSite"/>.
        /// </summary>
        /// <returns>
        /// The unique identifier for the <see cref="System.Web.Caching.CacheDependency" /> object.
        /// </returns>
        public override string GetUniqueID()
        {
            return uniqueId;
        }

        #endregion
    }
}